package com.template.contracts;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.ImmutableList;
import com.template.states.IouState;
import net.corda.core.contracts.Command;
import net.corda.core.contracts.CommandData;
import net.corda.core.contracts.Contract;
import net.corda.core.transactions.LedgerTransaction;

import static net.corda.core.contracts.ContractsDSL.requireThat;

/**
 * IOU Contract
 *
 * @author yangjie
 * @date 2020/12/04
 */
public class IouContract implements Contract {
    public static final String ID = IouContract.class.getName();

    @Override
    public void verify(LedgerTransaction tx) {
//        Assert.isTrue(CollUtil.size(tx.getCommands()) == 1, "tx must have one command.");
//
//        Command<Commands> command = tx.getCommand(0);
//        if (command.getValue() instanceof Commands.Create) {
//            // validate Shape
//            Assert.isTrue(CollUtil.isEmpty(tx.getInputs()), "tx can't have inputs.");
//            Assert.isTrue(CollUtil.size(tx.getOutputs()) == 1, "tx must have one outputs.");
//            IouState iouState = (IouState) tx.getOutput(0);
//            Assert.isTrue(iouState instanceof IouState, "the outputs state must is object of IocState.");
//
//            // validate Content
//            Assert.isTrue(ObjectUtil.notEqual(iouState.getLender(), iouState.getBorrower()), "lender not equal borrower.");
//            Assert.isTrue(iouState.getValue() > 0, "the value of iouState object must greater than 0");
//
//            // validate signers
//            Assert.isTrue(CollUtil.size(command.getSigners()) == 2, "command must have two signer.");
//            Assert.isTrue(command.getSigners().containsAll(ImmutableList.of(iouState.getLender().getOwningKey(), iouState.getBorrower().getOwningKey())), "the command must have lender,borrower signer.");
//        } else {
//            throw new IllegalArgumentException("not support other command.");
//        }

        requireThat(require -> {
            require.using("tx must have one command.", CollUtil.size(tx.getCommands()) == 1);
            return null;
        });

        final Command<Commands> command = tx.getCommand(0);
        if (command.getValue() instanceof Commands.Create) {
            requireThat(require -> {
                require.using("tx can't have inputs.", CollUtil.isEmpty(tx.getInputs()));
                require.using("tx must have one outputs.", CollUtil.size(tx.getOutputs()) == 1);
                IouState iouState = (IouState) tx.getOutput(0);
                require.using("the outputs state must is object of IocState.", iouState instanceof IouState);

                // validate Content
                require.using("lender must not equal borrower.", ObjectUtil.notEqual(iouState.getLender(), iouState.getBorrower()));
                require.using("the value of iouState object must greater than 0", iouState.getValue() > 0);

                // validate signers
                require.using("command must have two signer.", CollUtil.size(command.getSigners()) == 2);
                require.using("the command must have lender,borrower signer.",
                        command.getSigners().containsAll(ImmutableList.of(iouState.getLender().getOwningKey(), iouState.getBorrower().getOwningKey())));

                return null;
            });
        } else {
            throw new IllegalArgumentException("not support other command.");
        }
    }

    /**
     * Used to indicate the transaction's intent.
     */
    public interface Commands extends CommandData {
        /**
         * In our hello-world app, We will only have one command.
         */
        class Create implements Commands {
        }
    }
}